﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Threading;
using CommandWeb;



namespace Command
{

    public class PushService : IPushService
    {
        public CreateCurrencyRateResponse CreateCurrencyRate(CreateCurrencyRateRequest request)
        {
            CreateCurrencyRateResponse CurrencyRateResponse = new CreateCurrencyRateResponse();

            try
            {
                using (ExtRatesEntities context = new ExtRatesEntities())
                {
                    //add Currency if not exist
                    Currency Currency_Temp = context.Currency.Where(c => c.Name == request.CurrencyName).FirstOrDefault();
                    if (Currency_Temp == null)
                    {
                        Currency_Temp = new Currency()
                        {
                            Name = request.CurrencyName
                        };

                        context.AddToCurrency(Currency_Temp);
                        context.SaveChanges();
                    }

                    //add Period if not exist
                    Period PeriodTemp = context.Period.Where(c => c.DateTime == request.Period).FirstOrDefault();
                    if (PeriodTemp == null)
                    {
                        PeriodTemp = new Period()
                        {
                            DateTime = request.Period
                        };

                        context.AddToPeriod(PeriodTemp);
                        context.SaveChanges();
                    }

                    //add CurrancyRate
                    CurrencyRate CurrencyRateTemp = new CurrencyRate()
                    {
                        Period = PeriodTemp,
                        Currency = Currency_Temp,
                        Value = request.Value,
                    };
                    context.AddToCurrencyRate(CurrencyRateTemp);
                    context.SaveChanges();
                }

                CurrencyRateResponse.Status = ResponseStatus.OK;
            }
            catch (Exception ex)
            {
                CurrencyRateResponse.Status = ResponseStatus.Error;
            }

            return CurrencyRateResponse;
        }
        public CreateCurrencyRateResponse AddCurencyRate(CreateCurrencyRateRequest request)
        {
            CreateCurrencyRateResponse response = CreateCurrencyRate(request);

            Thread WriteCache_Thread = new Thread(delegate()
            {
                UpdateDay(request);
                UpdateWeek(request);
                UpdateMonth(request);
                UpdateYear(request);
            });
            WriteCache_Thread.Start();

            return response;
        }
        private void UpdateDay(CreateCurrencyRateRequest request)
        {
            using (ExtRatesEntities context = new ExtRatesEntities())
            {
                try
                {
                    DateTime DateBegin_Temp = new DateTime(request.Period.Year, request.Period.Month, request.Period.Day, 0, 0, 0);
                    DateTime DateEnd_Temp = DateBegin_Temp.AddDays(1);
                    int CurrancyID = context.Currency.Where(c => c.Name == request.CurrencyName).FirstOrDefault().ID;

                    //delete from DB
                    List<cache_Day> List_cache_Day_Temp = context.cache_Day.Where(c => c.Period <= DateEnd_Temp && c.Period >= DateBegin_Temp && c.CurrencyID == CurrancyID).ToList();
                    if (List_cache_Day_Temp != null)
                        foreach (cache_Day cache_Day_Temp in List_cache_Day_Temp)
                        {
                            context.DeleteObject(cache_Day_Temp);
                            context.SaveChanges();
                        }

                    //edit and add to DB
                    int DayFrequency = 12;
                    DateTime DateBegin_Part = DateBegin_Temp;
                    DateTime DateEnd_Part = DateBegin_Part.AddHours(2);
                    for (int PartWrapper = 0; PartWrapper < DayFrequency; PartWrapper++)
                    {
                        int DayFrequencyInPart = 5;
                        List<CurrencyRate> List_CurrencyRate_Temp = context.CurrencyRate.Where(c => c.Period.DateTime <= DateEnd_Part && c.Period.DateTime >= DateBegin_Part && c.Currency.ID == CurrancyID).ToList();
                        int DayFrequencyInPartReal = Math.Min(DayFrequencyInPart, List_CurrencyRate_Temp.Count);
                        double Koeficient = (double)List_CurrencyRate_Temp.Count / DayFrequencyInPartReal;

                        for (int Part = 0; Part < DayFrequencyInPartReal; Part++)
                        {
                            //calc average, max, min
                            double Average = 0;
                            double Max = double.MinValue;
                            double Min = double.MaxValue;
                            for (int k = Convert.ToInt32(Math.Truncate(Part * Koeficient)); k < Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)); k++)
                            {
                                Average += List_CurrencyRate_Temp[k].Value;
                                Max = Math.Max(Max, List_CurrencyRate_Temp[k].Value);
                                Min = Math.Min(Min, List_CurrencyRate_Temp[k].Value);
                            }
                            Average = Average / (Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)) - Convert.ToInt32(Math.Truncate(Part * Koeficient)));
                            //add to cache_Day
                            cache_Day cache_Day_Temp = new cache_Day()
                            {
                                Period = DateBegin_Part,
                                CurrencyID = CurrancyID,
                                Value = Average,
                                ValueMax = Max,
                                ValueMin = Min
                            };
                            context.AddTocache_Day(cache_Day_Temp);
                            context.SaveChanges();
                        }
                        for (int Part = DayFrequencyInPartReal; Part < DayFrequencyInPart; Part++)
                        {
                            //add to cache_Day
                            cache_Day cache_Day_Temp = new cache_Day()
                            {
                                Period = DateBegin_Part,
                                CurrencyID = CurrancyID,
                                Value = 0,
                                ValueMax = 0,
                                ValueMin = 0
                            };
                            context.AddTocache_Day(cache_Day_Temp);
                            context.SaveChanges();
                        }
                        DateBegin_Part = DateEnd_Part;
                        DateEnd_Part = DateEnd_Part.AddHours(2);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }
        private void UpdateWeek(CreateCurrencyRateRequest request)
        {
            using (ExtRatesEntities context = new ExtRatesEntities())
            {
                try
                {
                    DateTime DateBegin_Temp = new DateTime(request.Period.Year, request.Period.Month, request.Period.Day, 0, 0, 0);
                    while (DateBegin_Temp.DayOfWeek != DayOfWeek.Sunday)
                        DateBegin_Temp = DateBegin_Temp.AddDays(-1);
                    DateTime DateEnd_Temp = DateBegin_Temp.AddDays(7);
                    int CurrancyID = context.Currency.Where(c => c.Name == request.CurrencyName).FirstOrDefault().ID;

                    //delete from DB
                    List<cache_Week> List_cache_Week_Temp = context.cache_Week.Where(c => c.Period < DateEnd_Temp && c.Period >= DateBegin_Temp && c.CurrencyID == CurrancyID).ToList();
                    if (List_cache_Week_Temp != null)
                        foreach (cache_Week cache_Week_Temp in List_cache_Week_Temp)
                        {
                            context.DeleteObject(cache_Week_Temp);
                            context.SaveChanges();
                        }

                    int WeekFrequency = 7;
                    DateTime DateBegin_Part = DateBegin_Temp;
                    DateTime DateEnd_Part = DateBegin_Part.AddDays(1);
                    for (int PartWrapper = 0; PartWrapper < WeekFrequency; PartWrapper++)
                    {
                        int WeekFrequencyInPart = 6;
                        List<CurrencyRate> List_CurrencyRate_Temp = context.CurrencyRate.Where(c => c.Period.DateTime <= DateEnd_Part && c.Period.DateTime >= DateBegin_Part && c.Currency.ID == CurrancyID).ToList();
                        int WeekFrequencyInPartReal = Math.Min(WeekFrequencyInPart, List_CurrencyRate_Temp.Count);
                        double Koeficient = (double)List_CurrencyRate_Temp.Count / WeekFrequencyInPartReal;

                        for (int Part = 0; Part < WeekFrequencyInPartReal; Part++)
                        {
                            //calc average, max, min
                            double Average = 0;
                            double Max = double.MinValue;
                            double Min = double.MaxValue;
                            for (int k = Convert.ToInt32(Math.Truncate(Part * Koeficient)); k < Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)); k++)
                            {
                                Average += List_CurrencyRate_Temp[k].Value;
                                Max = Math.Max(Max, List_CurrencyRate_Temp[k].Value);
                                Min = Math.Min(Min, List_CurrencyRate_Temp[k].Value);
                            }
                            Average = Average / (Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)) - Convert.ToInt32(Math.Truncate(Part * Koeficient)));
                            //add to cache_Week
                            cache_Week cache_Week_Temp = new cache_Week()
                            {
                                Period = request.Period,
                                CurrencyID = CurrancyID,
                                Value = Average,
                                ValueMax = Max,
                                ValueMin = Min
                            };
                            context.AddTocache_Week(cache_Week_Temp);
                            context.SaveChanges();
                        }
                        for (int Part = WeekFrequencyInPartReal; Part < WeekFrequencyInPart; Part++)
                        {
                            //add to cache_Week
                            cache_Week cache_Week_Temp = new cache_Week()
                            {
                                Period = request.Period,
                                CurrencyID = CurrancyID,
                                Value = 0,
                                ValueMax = 0,
                                ValueMin = 0
                            };
                            context.AddTocache_Week(cache_Week_Temp);
                            context.SaveChanges();
                        }
                        DateBegin_Part = DateEnd_Part;
                        DateEnd_Part = DateEnd_Part.AddDays(1);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }
        private void UpdateMonth(CreateCurrencyRateRequest request)
        {
            using (ExtRatesEntities context = new ExtRatesEntities())
            {
                try
                {
                    DateTime DateBegin_Temp = new DateTime(request.Period.Year, request.Period.Month, 1, 0, 0, 0);
                    DateTime DateEnd_Temp = DateBegin_Temp.AddMonths(1);
                    int CurrancyID = context.Currency.Where(c => c.Name == request.CurrencyName).FirstOrDefault().ID;

                    //delete from DB
                    List<cache_Month> List_cache_Month_Temp = context.cache_Month.Where(c => c.Period < DateEnd_Temp && c.Period >= DateBegin_Temp && c.CurrencyID == CurrancyID).ToList();
                    if (List_cache_Month_Temp != null)
                        foreach (cache_Month cache_Month_Temp in List_cache_Month_Temp)
                        {
                            context.DeleteObject(cache_Month_Temp);
                            context.SaveChanges();
                        }

                    //add to DB
                    int MonthFrequency = 10;
                    DateTime DateBegin_Part = DateBegin_Temp;
                    DateTime DateEnd_Part = DateBegin_Part.AddDays(3);
                    for (int PartWrapper = 0; PartWrapper < MonthFrequency; PartWrapper++)
                    {
                        int MonthFrequencyInPart = 6;
                        List<CurrencyRate> List_CurrencyRate_Temp = context.CurrencyRate.Where(c => c.Period.DateTime <= DateEnd_Part && c.Period.DateTime >= DateBegin_Part && c.Currency.ID == CurrancyID).ToList();
                        int MonthFrequencyInPartReal = Math.Min(MonthFrequencyInPart, List_CurrencyRate_Temp.Count);
                        double Koeficient = (double)List_CurrencyRate_Temp.Count / MonthFrequencyInPartReal;

                        for (int Part = 0; Part < MonthFrequencyInPartReal; Part++)
                        {
                            //calc average, max, min
                            double Average = 0;
                            double Max = double.MinValue;
                            double Min = double.MaxValue;
                            for (int k = Convert.ToInt32(Math.Truncate(Part * Koeficient)); k < Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)); k++)
                            {
                                Average += List_CurrencyRate_Temp[k].Value;
                                Max = Math.Max(Max, List_CurrencyRate_Temp[k].Value);
                                Min = Math.Min(Min, List_CurrencyRate_Temp[k].Value);
                            }
                            Average = Average / (Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)) - Convert.ToInt32(Math.Truncate(Part * Koeficient)));
                            //add to cache_Month
                            cache_Month cache_Month_Temp = new cache_Month()
                            {
                                Period = request.Period,
                                CurrencyID = CurrancyID,
                                Value = Average,
                                ValueMax = Max,
                                ValueMin = Min
                            };
                            context.AddTocache_Month(cache_Month_Temp);
                            context.SaveChanges();
                        }
                        for (int Part = MonthFrequencyInPartReal; Part < MonthFrequencyInPart; Part++)
                        {
                            //add to cache_Month
                            cache_Month cache_Month_Temp = new cache_Month()
                            {
                                Period = request.Period,
                                CurrencyID = CurrancyID,
                                Value = 0,
                                ValueMax = 0,
                                ValueMin = 0
                            };
                            context.AddTocache_Month(cache_Month_Temp);
                            context.SaveChanges();
                        }
                        DateBegin_Part = DateEnd_Part;
                        DateEnd_Part = DateEnd_Part.AddDays(3);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }
        private void UpdateYear(CreateCurrencyRateRequest request)
        {
            using (ExtRatesEntities context = new ExtRatesEntities())
            {
                try
                {
                    DateTime DateBegin_Temp = new DateTime(request.Period.Year, 1, 1, 0, 0, 0);
                    DateTime DateEnd_Temp = DateBegin_Temp.AddYears(1);
                    int CurrancyID = context.Currency.Where(c => c.Name == request.CurrencyName).FirstOrDefault().ID;

                    //delete from DB
                    List<cache_Year> List_cache_Year_Temp = context.cache_Year.Where(c => c.Period < DateEnd_Temp && c.Period >= DateBegin_Temp && c.CurrencyID == CurrancyID).ToList();
                    if (List_cache_Year_Temp != null)
                        foreach (cache_Year cache_Year_Temp in List_cache_Year_Temp)
                        {
                            context.DeleteObject(cache_Year_Temp);
                            context.SaveChanges();
                        }

                    //add to DB
                    int YearFrequency = 12;
                    DateTime DateBegin_Part = DateBegin_Temp;
                    DateTime DateEnd_Part = DateBegin_Part.AddDays(3);
                    for (int PartWrapper = 0; PartWrapper < YearFrequency; PartWrapper++)
                    {
                        int YearFrequencyInPart = 6;
                        List<CurrencyRate> List_CurrencyRate_Temp = context.CurrencyRate.Where(c => c.Period.DateTime <= DateEnd_Part && c.Period.DateTime >= DateBegin_Part && c.Currency.ID == CurrancyID).ToList();
                        int YearFrequencyInPartReal = Math.Min(YearFrequencyInPart, List_CurrencyRate_Temp.Count);
                        double Koeficient = (double)List_CurrencyRate_Temp.Count / YearFrequencyInPartReal;

                        for (int Part = 0; Part < YearFrequencyInPartReal; Part++)
                        {
                            //calc average, max, min
                            double Average = 0;
                            double Max = double.MinValue;
                            double Min = double.MaxValue;
                            for (int k = Convert.ToInt32(Math.Truncate(Part * Koeficient)); k < Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)); k++)
                            {
                                Average += List_CurrencyRate_Temp[k].Value;
                                Max = Math.Max(Max, List_CurrencyRate_Temp[k].Value);
                                Min = Math.Min(Min, List_CurrencyRate_Temp[k].Value);
                            }
                            Average = Average / (Convert.ToInt32(Math.Truncate((Part + 1) * Koeficient)) - Convert.ToInt32(Math.Truncate(Part * Koeficient)));
                            //add to cache_Year
                            cache_Year cache_Year_Temp = new cache_Year()
                            {
                                Period = request.Period,
                                CurrencyID = CurrancyID,
                                Value = Average,
                                ValueMax = Max,
                                ValueMin = Min
                            };
                            context.AddTocache_Year(cache_Year_Temp);
                            context.SaveChanges();
                        }
                        for (int Part = YearFrequencyInPartReal; Part < YearFrequencyInPart; Part++)
                        {
                            //add to cache_Year
                            cache_Year cache_Year_Temp = new cache_Year()
                            {
                                Period = request.Period,
                                CurrencyID = CurrancyID,
                                Value = 0,
                                ValueMax = 0,
                                ValueMin = 0
                            };
                            context.AddTocache_Year(cache_Year_Temp);
                            context.SaveChanges();
                        }
                        DateBegin_Part = DateEnd_Part;
                        DateEnd_Part = DateEnd_Part.AddDays(3);
                    }
                }
                catch (Exception ex)
                {

                }
            }
        }

    }

}
